/**
 * @file scanner-character-streams.cc
 * @author your name (you@domain.com)
 * @brief 
 * @version 0.1
 * @date 2024-04-01
 * 
 * @copyright Copyright (c) 2024
 * 
 */
#include "src/parsing/scanner-character-streams.h"
#include <memory>
#include <vector>


#include "src/parsing/scanner.h"

template <typename Char>
struct Range {
  const Char* start;
  const Char* end;

  size_t length() { return static_cast<size_t>(end - start); }
  bool unaligned_start() const {
    return reinterpret_cast<intptr_t>(start) % sizeof(Char) == 1;
  }
};

template <typename Char>
class ExternalStringStream {
    using ExternalString = char*;

    public:
    ExternalStringStream(ExternalString string, size_t start_offset,
                        size_t length)
        : data_(reinterpret_cast<const uint8_t*>(string) + start_offset),
            length_(length) {
              std::cout << "ExternalStringStream data_0:\t" << data_ << std::endl;
                std::cout << "ExternalStringStream length:\t" << length << std::endl;
            }

    ExternalStringStream(const ExternalStringStream& other) 
        : data_(other.data_),
            length_(other.length_) {}

    // The no_gc argument is only here because of the templated way this class
    // is used along with other implementations that require V8 heap access.
    Range<Char> GetDataAt(size_t pos) {
        std::cout << "GetDataAt1\t" << pos << std::endl;
        std::cout << "GetDataAt2\t" << data_[0] << std::endl;
        std::cout << "GetDataAt3\t" << data_ << std::endl;
        return {&data_[std::min(length_, pos)], &data_[length_]};
    }

    void Data() {
      std::cout << "==Data==>" << data_ << std::endl;
    }

    static const bool kCanBeCloned = true;
    static const bool kCanAccessHeap = false;

    private:
        const Char* const data_;
        const size_t length_;
};

template <template <typename T> class ByteStream>
class BufferedCharacterStream : public Utf16CharacterStream {
 public:
  template <class... TArgs>
  BufferedCharacterStream(size_t pos, TArgs... args) : byte_stream_(args...) {
    std::cout << "BufferedCharacterStream" << std::endl;
    byte_stream_.Data();
    buffer_pos_ = pos;
  }

  std::unique_ptr<Utf16CharacterStream> Clone() const override {
    //CHECK(can_be_cloned());
    return std::unique_ptr<Utf16CharacterStream>(
        new BufferedCharacterStream<ByteStream>(*this));
  }

 protected:
  bool ReadBlock(size_t position) final {
    std::cout << "ReadBlock" << std::endl;
    buffer_pos_ = position;
    buffer_start_ = &buffer_[0];
    buffer_cursor_ = buffer_start_;

    Range<uint8_t> range =
        byte_stream_.GetDataAt(position);
    if (range.length() == 0) {
      buffer_end_ = buffer_start_;
      return false;
    }

    size_t length = std::min({kBufferSize, range.length()});
    //memcpy(buffer_, range.start, length);
    for(int i = 0; i < length; i++) {
      buffer_[i] = *(range.start + i);
    }
    std::cout << "buffer_\t" << (*buffer_start_) << std::endl;
    buffer_end_ = &buffer_[length];
    return true;
  }

  void PrintData() final {
    byte_stream_.Data();
  }

 private:
  BufferedCharacterStream(const BufferedCharacterStream<ByteStream>& other)
      : byte_stream_(other.byte_stream_) {}

  static const size_t kBufferSize = 512;
  base::uc16 buffer_[kBufferSize];
  ByteStream<uint8_t> byte_stream_;
};

Utf16CharacterStream* ScannerStream::For(char* data) {
    return ScannerStream::For(data, 0, 12);
}

Utf16CharacterStream* ScannerStream::For(char* data, int start_pos, int end_pos) {
    size_t start_offset = 0;
    std::cout << "ScannerStream::For begin end_pos:\t" << end_pos << std::endl;
    Utf16CharacterStream* utf18Stream = new BufferedCharacterStream<ExternalStringStream>(
        static_cast<size_t>(start_pos), data,
        start_offset, static_cast<size_t>(end_pos));
    std::cout << "ScannerStream::For end end_pos:\t" << end_pos << std::endl;
    return utf18Stream;
}